using System.Collections.Generic;

namespace Core
{
    /// <summary>
    /// A*��ͼ
    /// </summary>
    public class SquareGrid
    {
        private static readonly Node[] Dirs = new[]
        {
            new Node(1, 0),     // right
            new Node(0, -1),    // bot
            new Node(-1, 0),    // left
            new Node(0, 1),     // top
            new Node(1, 1),     // right-top
            new Node(-1, 1),    // left-top
            new Node(1, -1),    // right-bot
            new Node(-1, -1),   // left-bot
        };

        public int Width, Height;
        public readonly Dictionary<int, Node> NodeMaps = new ();

        public SquareGrid(int width, int height)
        {
            this.Width = width;
            this.Height = height;
        }

        /// <summary>
        /// �жϱ߽�
        /// </summary>
        public bool InBounds(Node node)
        {
            return 0 <= node.X && node.X < Width
                && 0 <= node.Y && node.Y < Height;
        }

        /// <summary>
        /// �жϿ�ͨ�� 
        /// </summary>
        public bool Passable(Node node)
        {
            return true;
        }

        public DefaultAStarCost DefaultCost = new();
        /// <summary>
        /// �жϴӽڵ�a���ڵ�b�ƶ�����
        /// </summary>
        public float Cost(Node lhs, Node rhs)
        {
            return DefaultCost.Cost(lhs, rhs);
        }

        /// <summary>
        /// �Ե�ǰ�ڵ�Ϊ������8������Ѱ��·�� 
        /// </summary>
        public IEnumerable<Node> Neighbors(Node node)
        {
            for (int i = 0; i < Dirs.Length; ++i)
            {
                var dir = Dirs[i];
                // ����Ҫ����new��������һ���Ӱѵ�ͼȫ�����������Node����Ϊ������ʵֻ��Ҫ·�������ݣ���ʱ��ֻ��Ҫ��Brick����������һ�¾ͺ���
                var x = node.X + dir.X;
                var z = node.Y + dir.Y;
                var neighborsNode = GetNode(x, z);
                if (InBounds(neighborsNode) && Passable(neighborsNode))
                {
                    yield return neighborsNode;
                }
            }
        }

        /// <summary>
        /// ��ȡ�ڵ�
        /// </summary>
        /// <param name="x">x����</param>
        /// <param name="z">z����</param>
        public Node GetNode(int x, int z)
        {
            var key = (x << 8) + z; // ֻʹ��int��16λ����8λ��x����8λ��z
            if (NodeMaps.ContainsKey(key) == false)
            {
                var node= ReferencePool.Acquire<Node>();
                node.X = x;
                node.Y = z;
                NodeMaps[key] = node;
            }

            return NodeMaps[key];
        }
    }
}
